package fun.tan90.base.util;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class BaseUtil {

    public static final double R = 6372795.477598; // 地球半径，单位米

    /**
     * 计算两个GPS坐标之间的距离
     * Haversine
     *
     * @param lat1 点A纬度（度）
     * @param lon1 点A经度（度）
     * @param lat2 点B纬度（度）
     * @param lon2 点B经度（度）
     * @return 距离（米）
     */
    public static long calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        // 将经纬度从度转换为弧度
        double radLat1 = Math.toRadians(lat1);
        double radLon1 = Math.toRadians(lon1);
        double radLat2 = Math.toRadians(lat2);
        double radLon2 = Math.toRadians(lon2);
        // 计算经纬度差
        double deltaLat = radLat2 - radLat1;
        double deltaLon = radLon2 - radLon1;
        // Haversine公式
        double a = Math.pow(Math.sin(deltaLat / 2), 2)
                + Math.cos(radLat1) * Math.cos(radLat2)
                * Math.pow(Math.sin(deltaLon / 2), 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return BigDecimal.valueOf(R * c).setScale(0, RoundingMode.HALF_UP).longValue();
    }

    /**
     * 计算从点A(lat1, lon1)到点B(lat2, lon2)的方位角（与正北的夹角，单位：度）
     */
    public static Integer calculateBear(double lat1, double lon1, double lat2, double lon2) {
        // 转换为弧度
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);
        // 计算经度差
        double deltaLon = lon2Rad - lon1Rad;
        // 计算y和x分量
        double y = Math.sin(deltaLon) * Math.cos(lat2Rad);
        double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(deltaLon);
        // 计算方位角弧度并转换为度数
        double bearingDeg = Math.toDegrees(Math.atan2(y, x));
        // 调整到0-360度
        return BigDecimal.valueOf((bearingDeg + 360) % 360).setScale(0, RoundingMode.HALF_UP).intValue() % 360;
    }

    /**
     * 判断点C位于线段AB的哪一侧
     *
     * @param latA 点A纬度
     * @param lonA 点A经度
     * @param latB 点B纬度
     * @param lonB 点B经度
     * @param latC 点C纬度
     * @param lonC 点C经度
     * @return 1（左侧）、-1（右侧）、0（线上）
     */
    public static int determineSide(double latA, double lonA, double latB, double lonB, double latC, double lonC) {
        double cross = (lonB - lonA) * (latC - latA) - (latB - latA) * (lonC - lonA);
        if (cross > 1e-9) {  // 考虑浮点误差
            return 1; // 左侧
        } else if (cross < -1e-9) {
            return -1; // 右侧
        } else {
            return 0; // 在线上
        }
    }
}
